<?php
/**
 * User: 苏翔
 * Date: 2024/8/11 19:01
 */

namespace App\Service;

use App\Dao\HscoinBalanceDao;
use App\Dao\HscoinBillDao;
use App\Dao\HscoinDividendDao;
use App\HscoinConf;

use Hyperf\Di\Annotation\Inject;


/**
 * 分红 测试例子
 * $c = \App\Service\HscoinDividendService::class;
 * $cls_name = $c;
 * $c = $container->get($c);
 * $date = date('Y-m-d', time() );
 * $rs= $c->register($date); // 分红等级
 * $rs = $c->dividend($date, 0.5, 1); // 分红按默认某日某时进行分红
 * $c = $this->request->input('c', '');
 * $a = $this->request->input('a', '');
 * $data = compact('rs', 'cls_name', 'c');
 * return $this->jsonSuccess($data);
 */

/**
 * CREATE TABLE `hscoin_dividend` (
 * `id` int unsigned NOT NULL AUTO_INCREMENT,
 * `uid` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户uid',
 * `register_date` date DEFAULT NULL COMMENT '登记日',
 * `balance` decimal(11,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '收入统计',
 * `distribute_amount` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '分红额度',
 * `status` tinyint NOT NULL DEFAULT '0' COMMENT '发放状态',
 * `handle_time` datetime DEFAULT NULL COMMENT '发放时间',
 * PRIMARY KEY (`id`),
 * KEY `uid` (`register_date`,`uid`) USING BTREE
 * ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='by苏翔：分红登记：有重复检查，一次事务；有数据库方案，不依赖服务;索引register_date,uid\r\n分红发放：登记日期T日之后，指定发放某人登记分红\r\n\r\n';
 */
/**
 * 注释一下分红写入：
 * register 方法 注册就是登记日
 * dividend 方法就是分红
 * 配置再定时任务，更加定时按比例放大
 * @todo 应该无条件，后续在分红时根据索引 register_date+uid 设置状态
 * @method getList($uid = 0, $category = 0, $min_id = 0, $max_id = 0, $size = 10)
 */
class HscoinDividendService extends BaseService
{

    #[Inject]
    protected HscoinDividendDao $dao;

    #[Inject]
    protected HscoinBillDao $billDao;
    const STATUS_WAIT = 0;
    const STATUS_START = 1;
    const STATUS_FINISH = 2;
    const STATUS_ERROR_NOT_ENOUGH = 3;
    const STATUS_ERROR_BILL_ERROR = 99;


    /**
     * 执行登记
     * @return bool
     */
    function register()
    {
        $date = date('Y-m-d');
        if ($this->isRegistered($date)) {
            return true;
        }
        $sql = "INSERT INTO hscoin_dividend ( register_date, uid, balance ) SELECT
                '$date',
                uid,
                cnt 
                FROM
	            hscoin_balance where  uid>0 and cnt >0";//
        return $this->dao->getModel()->getConnection()->statement($sql);
    }

    function isRegistered($date)
    {
        return $this->dao->getModel()->where('register_date', $date)->value('id');
    }


    /**
     * 执行分红
     * @param $register_date
     * @param $rate
     * @param $type
     * @return void
     * @throws \Throwable
     */
    function dividend($register_date, $rate, $type = 1)
    {
        $table = $this->dao->getModel()->getTable();
        $isHandleNext = true;
        $this->dao->getModel()->getConnection()->transaction(function () use (&$isHandleNext, $register_date, $rate, $type) {
            $rs = $this->dao->getModel()->where('register_date', $register_date)->where('status', self::STATUS_WAIT)->first();

            if (!$rs) {
                $isHandleNext = false;
                return;
            }
            $handle = $this->handleTrans($rs, $rate, $type);
            if (!$handle) {
                $isHandleNext = false;
            }
        });
        if ($isHandleNext) {
            $this->dividend($register_date, $rate, $type);
        }
    }

    function handleTrans($rs, $rate, $type)
    {
        if (!$rs->uid) {
            return $this->setStatus($rs->id, self::STATUS_FINISH);
        }
        $this->setStatus($rs->id, self::STATUS_START);
        $distribute_amount = round($rs->balance * $rate / 100, 2);
        $rs->type = $type;
        $rs->handle_time = date('Y-m-d H:i:s');
        if ($distribute_amount < 0.01) {

            return $this->setStatus($rs->id, self::STATUS_ERROR_NOT_ENOUGH);

        }
        $category = HscoinConf::CATEGORY_INCOME_DIVIDEND;


        $rsBill = $this->billDao->add($category, $rs->id, $rs->balance, $distribute_amount, $rs->uid, '分红');
        $insertId = $rsBill[0] ?? 0;
        $state = $insertId ? self::STATUS_FINISH : self::STATUS_ERROR_BILL_ERROR;
        return $this->setStatus($rs->id, $state);
    }

    function setStatus($id, $status)
    {
        return $this->dao->getModel()->where('id', $id)->update(['status' => $status]);
    }
}